/*
 * Copyright (c) 2017-2019, Lindenis Tech. Ltd.
 * All rights reserved.
 *
 * File:
 *
 * Description:
 *
 * Author:
 *      xiaoshujun@lindeni.com
 *
 * Create Date:
 *      2020/06/30
 *
 * History:
 *
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "osal_loop_array.h"
#include "osal_log.h"

typedef struct _loop_array_ctx_t
{
    unsigned int    total;
    unsigned int    i_read;
    unsigned int    i_write;
    lock_mutex      mutex;
} loop_array_ctx_t;

_handle_t loop_array_create(int max)
{
    loop_array_ctx_t * p_ctx = malloc(sizeof(loop_array_ctx_t));
    if (p_ctx == NULL)
    {
        return (_handle_t)NULL;
    }

    memset(p_ctx, 0, sizeof(loop_array_ctx_t));
    p_ctx->total = max;

    init_lock(&p_ctx->mutex);

    return (_handle_t)p_ctx;
}

void loop_array_destroy(_handle_t h_arr)
{
    loop_array_ctx_t * p_ctx = (loop_array_ctx_t *)h_arr;
    if (p_ctx != NULL)
    {
        destroy_lock(&p_ctx->mutex);
        free(p_ctx);
        p_ctx = NULL;
    }
}

int loop_array_try_pop(_handle_t h_arr)
{
    loop_array_ctx_t * p_ctx = (loop_array_ctx_t *)h_arr;
    int index = -1;

    if (p_ctx == NULL)
    {
        return -1;
    }

    do_lock(&p_ctx->mutex);
    if (p_ctx->i_read < p_ctx->i_write)
    {
        index = p_ctx->i_read % p_ctx->total;
    }
    do_unlock(&p_ctx->mutex);

    return index;
}

/*
 * must called after loop_array_try_pop()
 */
void loop_array_popped(_handle_t h_arr)
{
    loop_array_ctx_t * p_ctx = (loop_array_ctx_t *)h_arr;
    if (p_ctx == NULL)
    {
        return;
    }

    do_lock(&p_ctx->mutex);
    p_ctx->i_read++;
    do_unlock(&p_ctx->mutex);
}

int loop_array_try_push(_handle_t h_arr)
{
    loop_array_ctx_t * p_ctx = (loop_array_ctx_t *)h_arr;
    int index = -1;

    if (p_ctx == NULL)
    {
        return -1;
    }

    do_lock(&p_ctx->mutex);
    if ((p_ctx->i_write >= p_ctx->i_read)
        && (p_ctx->i_write - p_ctx->i_read < p_ctx->total))
    {
        index = p_ctx->i_write % p_ctx->total;
    }
    do_unlock(&p_ctx->mutex);

    return index;
}

/*
 * must called after loop_array_try_push()
 */
void loop_array_pushed(_handle_t h_arr)
{
    loop_array_ctx_t * p_ctx = (loop_array_ctx_t *)h_arr;
    if (p_ctx == NULL)
    {
        return;
    }

    do_lock(&p_ctx->mutex);
    p_ctx->i_write++;
    do_unlock(&p_ctx->mutex);
}

void loop_array_dump(_handle_t h_arr)
{
    loop_array_ctx_t * p_ctx = (loop_array_ctx_t *)h_arr;
    if (p_ctx == NULL)
    {
        return;
    }

    logv("i_read: %d(%d), i_write: %d(%d), total: %d",
        p_ctx->i_read % p_ctx->total, p_ctx->i_read,
        p_ctx->i_write % p_ctx->total, p_ctx->i_write,
        p_ctx->total);
}

